package ferp.android.services;

import ferp.core.card.Card;
import ferp.core.game.Game;
import ferp.core.game.Settings;
import ferp.core.mode.Moving;

/**
 * User: olegs
 * Date: 08/05/2014 12:03
 */
public class ServiceProxy
{
  public static void preallocate(IResolverService2 service) throws ServiceException
  {
    try
    {
      checkStatus(service, service.preallocate(), "preallocate");
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static void initialize(IResolverService2 service, Game g, Settings settings) throws ServiceException
  {
    try
    {
      // populate hands array
      hands[0] = g.getHand(0).initial;
      hands[1] = g.getHand(1).initial;
      hands[2] = g.getHand(2).initial;

      // call initialization routine
      checkStatus(service,
                  service.initialize(((Moving)g.mode()).evaluator(), g.player.declarer, Game.next(g.player.dealer),
                                     g.trump().ordinal(), hands, g.getTalonCompressed(0), g.getTalonCompressed(1),
                                     g.type == Game.Type.UNKNOWN || g.isOpen(), settings.isRostov(), g.sets, g.getResolverDrop()), "initialize");

      checkStatus(service, g.service.memory = service.getAvailableMemory(), "getAvailableMemory");
      checkStatus(service, g.service.nodes = service.getNodePoolCapacity(), "getNodePoolCapacity");
      checkStatus(service, g.service.moves = service.getMovePoolCapacity(), "getMovePoolCapacity");
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static int getBestScore(IResolverService2 service) throws ServiceException
  {
    try
    {
      int score = service.getBestScore();

      checkStatus(service, score, "getBestScore");

      return score;
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static byte getBestMove(IResolverService2 service, int level, int hand, int trick, int cardInHand) throws ServiceException
  {
    try
    {
      byte move = service.getBestMove(level, hand, trick, cardInHand);

      checkStatus(service, move, "getBestMove");

      if (!Card.isValidIndex(move))
        throw new ServiceException("getBestMove returned " + move + "\n" + service.getExceptionTrace());

      return move;
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static void solve(IResolverService2 service) throws ServiceException
  {
    try
    {
      checkStatus(service, service.solve(), "solve");
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static void advance(IResolverService2 service, int hand, int trick) throws ServiceException
  {
    try
    {
      checkStatus(service, service.advance(hand, trick), "advance");
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static void recalculateOnNextSolve(IResolverService2 service, int trick) throws ServiceException
  {
    try
    {
      checkStatus(service, service.recalculateOnNextSolve(trick), "recalculateOnNextSolve");
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  public static int getSpeed(IResolverService2 service) throws ServiceException
  {
    try
    {
      int speed = service.getSpeed();

      checkStatus(service, speed, "getSpeed");

      return speed;
    }
    catch (ServiceException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      throw new ServiceException(e);
    }
  }

  private static final int[] hands = new int[Game.PLAYERS];

  private static void checkStatus(IResolverService2 service, long status, String method) throws ServiceException
  {
    if (status <= 0)
      switch ((int)status)
      {
        case ResolverService2.OK:
          break;

        case ResolverService2.OUT_OF_MEMORY:
          throw new ServiceException(method + " failed due to out of memory exception in service", status);

        default:
          try
          {
            throw new ServiceException(method + " returned " + status + "\n" + service.getExceptionTrace(), status);
          }
          catch (ServiceException e)
          {
            throw e;
          }
          catch (Exception e)
          {
            throw new ServiceException(e);
          }
      }
  }
}
